﻿using System;
using System.IO;

namespace SharpOSCAR.Base
{
    /// <summary>
    /// TLVs are a very common structure used in the OSCAR protocol to represent dynamically typed data. 
    /// Parsers should always ignore unknown tags as to not break old clients when new protocol items
    /// are added. Possible values for tags are determined by where the TLV is in the protocol; 
    /// these possible values belong to a TLV class. 
    /// </summary>
    /// <remarks>
    /// TLVs are usually used in an array of TLV form, allowing the protocol to easily be expanded. 
    /// Having just one TLV without an array does not gain much since it only allows one item to be
    /// described. There are two common methods for adding an array of TLVs to datatypes and SNACs.
    /// An additional method also exists to add an array of TLVs to SNACs. 
    /// The most common is a tlvBlock which is a u16 number of TLVs followed by that many TLVs. 
    /// The less common is a tlvLBlock which instead of counting the number of TLVs, counts the size
    /// of all the TLVs. The third, which is only available in SNACs, is the tlvRestBlock which says
    /// any remaining bytes in the SNAC are TLVs. 
    /// </remarks>
    public class Tlv : ProtocolData
    {
        private U16 _Tag;
        /// <summary>
        /// Numeric tag of the data, possible values are defined in the TLV class for the group of TLVs
        /// </summary>
        public ushort Tag
        {
            get { return _Tag.Value; }
            set { _Tag.Value = value; }
        }

        /// <summary>
        /// Length in bytes of the variable in data
        /// </summary>
        public ushort Length
        {
            get { return Convert.ToUInt16(_Blob.Length); }
        }

        private byte[] _Blob;
        /// <summary>
        /// The data inside the TLV of len length; usually another datatype is used to represent the
        /// data - this is described in the TLV class
        /// </summary>
        public byte[] Blob
        {
            get { return _Blob; }
            set { _Blob = value; }
        }

        /// <summary>
        /// Initializes the TLV with the specified tag
        /// </summary>
        /// <param name="tag">Tag</param>
        public Tlv(ushort tag)
        {
            _Tag = new U16(tag);
        }

        /// <summary>
        /// Initializes the TLV with the specified tag and payload
        /// </summary>
        /// <param name="tag">Tag</param>
        /// <param name="payload">Payload of the Tlv</param>
        public Tlv(ushort tag, ProtocolData payload)
        {
            _Tag = new U16(tag);
            _Blob = payload.ToByteArray();
        }

        /// <summary>
        /// Converts the Tlv into a byte array of data
        /// </summary>
        /// <returns>Returns the Tlv in a byte array</returns>
        public override byte[] ToByteArray()
        {
            using (MemoryStream ms = new MemoryStream())
            {
                _Tag.WriteToStream(ms);
                U16 lenBytes = new U16(Length);
                lenBytes.WriteToStream(ms);
                ms.Write(_Blob, 0, _Blob.Length);
                return ms.ToArray();
            }
        }
    }
}
